package com.cxyjy.common.util;


import com.cxyjy.common.BusinessException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
import java.io.*;
import java.net.ConnectException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.Base64;
import java.util.Comparator;
import java.util.Iterator;

/**
 * @Author: jony
 * @Date : 2024/11/20 09:36
 * @VERSION v1.0
 */
@Slf4j
public class JFileUtil {
    // 定义常量
    private static final byte[] PNG_HEADER = {(byte) 0x89, 0x50, 0x4E, 0x47};
    private static final byte[] JPEG_HEADER = {(byte) 0xFF, (byte) 0xD8, (byte) 0xFF};
    private static final byte[] GIF_HEADER = {'G', 'I', 'F'};
    private static final byte[] BMP_HEADER = {'B', 'M'};
    private static final byte[] WEBP_RIFF_HEADER = {'R', 'I', 'F', 'F'};
    private static final byte[] WEBP_WEBP_HEADER = {'W', 'E', 'B', 'P'};


    /**
     * 下载图片并返回其 BufferedImage 和真实扩展名
     */
    public static String getImageFormat(String imageUrl) throws IOException {
        URL url = new URL(imageUrl);
        URLConnection connection = url.openConnection();
        connection.setRequestProperty("User-Agent", "Mozilla/5.0");

        try (InputStream inputStream = connection.getInputStream()) {

            // 第一步：将流缓存为字节数组
            byte[] imageData;
            try (ByteArrayOutputStream buffer = new ByteArrayOutputStream()) {
                int nRead;
                byte[] data = new byte[1024];
                while ((nRead = inputStream.read(data, 0, data.length)) != -1) {
                    buffer.write(data, 0, nRead);
                }
                buffer.flush();
                imageData = buffer.toByteArray();
            }

            // 第二步：用内存中的字节数组创建 InputStream，用于检测格式
            try (InputStream bais1 = new ByteArrayInputStream(imageData)) {
                String formatName = detectImageFormat(bais1);
                String extension = mapFormatToExtension(formatName);
                return extension;
            }
        }
    }

    /**
     * 检测图片的真实格式，基于 Magic Number（文件头）
     *
     * @param inputStream 图片输入流（必须支持 mark/reset）
     * @return 格式名称（小写），如 "png", "jpeg", "gif", "bmp", "webp"，未知返回 null
     * @throws IOException 如果读取失败
     */
    public static String detectImageFormat(InputStream inputStream) throws IOException {
        if (!inputStream.markSupported()) {
            inputStream = new java.io.BufferedInputStream(inputStream);
        }

        inputStream.mark(12); // 最多读取12个字节用于识别
        byte[] header = new byte[12];
        int bytesRead = inputStream.read(header);
        inputStream.reset(); // 重置流以便后续使用

        if (bytesRead >= 3) {
            // JPEG 判断
            if (matches(JPEG_HEADER, header, 0)) {
                return "jpeg";
            }
        }

        if (bytesRead >= 4) {
            // PNG 判断
            if (matches(PNG_HEADER, header, 0)) {
                return "png";
            }

            // GIF 判断
            if (matches(GIF_HEADER, header, 0)) {
                return "gif";
            }

            // BMP 判断
            if (matches(BMP_HEADER, header, 0)) {
                return "bmp";
            }

            // WebP 判断（RIFF + WEBP）
            if (matches(WEBP_RIFF_HEADER, header, 0) && bytesRead >= 12 &&
                    matches(WEBP_WEBP_HEADER, header, 8)) {
                return "webp";
            }
        }

        return null; // 未知格式
    }

    // 辅助方法：判断 header 是否在 offset 处匹配 target
    private static boolean matches(byte[] target, byte[] buffer, int offset) {
        for (int i = 0; i < target.length; i++) {
            if (buffer[offset + i] != target[i]) {
                return false;
            }
        }
        return true;
    }

    /**
     * 将multipartFile转换为file
     *
     * @param multipartFile
     * @return
     * @throws IOException
     */
    public static File multipartfileToFile(MultipartFile multipartFile) throws IOException {
        String fileName = multipartFile.getOriginalFilename();
        String extension = "";
        //不要后缀名
        String fileNameWithoutExtension = "";
        if (JObjectUtil.isNotEmpty(fileName) && fileName.contains(".")) {
            // 返回最后一个 "." 之后的部分作为后缀名
            extension = fileName.substring(fileName.lastIndexOf(".") + 1);
            fileNameWithoutExtension = fileName.substring(0, fileName.lastIndexOf("."));
        } else {

        }
        // 创建临时目录存放临时文件，因为这样可以按原来的文件名转换成文件比较方便
        Path tempDir = Files.createTempDirectory("myTempDir_");
        String tempImageFileName = fileNameWithoutExtension + "." + extension;
        File tempImageFile = new File(tempDir.toFile(), tempImageFileName);
        boolean fileCreated = tempImageFile.createNewFile();
        if (fileCreated) {
//            log.info("A user just uploaded an image named " + tempImageFile.getName());
        }
        try {
            multipartFile.transferTo(tempImageFile);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return tempImageFile;
    }

    /**
     * 检查上传的文件的后缀名是否符合要求
     * 符合的话返回true
     *
     * @param multipartFile
     * @param expectedExtensions
     * @return
     */
    public static boolean checkFileExtension(MultipartFile multipartFile, String[] expectedExtensions) {
        if (multipartFile == null || multipartFile.getOriginalFilename() == null || expectedExtensions == null || expectedExtensions.length == 0) {
            return false;
        }

        //获取文件名
        String fileName = multipartFile.getOriginalFilename();
        return isEqualsToExpected(fileName, expectedExtensions);

    }

    public static boolean checkFileExtension(String imageUrlStr, String[] expectedExtensions) throws IOException {
        String extension = getImageFormat(imageUrlStr);
        return isEqualsToExpected(extension, expectedExtensions);
    }

    /**
     * MultipartFile类型文件转为base64格式
     *
     * @param multipartFile
     * @return
     * @throws Exception
     */
    public static String convertToBase64(MultipartFile multipartFile) throws Exception {
        // 1. 校验文件是否为空
        if (multipartFile == null || multipartFile.isEmpty()) {
            throw new IllegalArgumentException("文件不能为空");
        }

        // 2. 读取文件字节数组
        byte[] fileBytes = multipartFile.getBytes();

        // 3. 使用Base64编码（URL安全模式，避免出现+/=符号）
        return Base64.getEncoder().encodeToString(fileBytes);
    }



    /**
     * 获取图片的真实格式名称（如 jpg, png）
     */
    private static String getRealImageFormat(InputStream imageStream) throws IOException {
        // 重置输入流到开头
        if (imageStream.markSupported()) {
            imageStream.reset();
        }

        // 创建 ImageInputStream
        ImageInputStream iis = ImageIO.createImageInputStream(imageStream);
        if (iis == null) {
            throw new IOException("无法创建 ImageInputStream");
        }

        // 获取能读取该图像的阅读器
        Iterator<ImageReader> readers = ImageIO.getImageReaders(iis);

        if (readers.hasNext()) {
            ImageReader reader = readers.next();
            try {

                String formatName = reader.getFormatName();
                return formatName.toLowerCase();
            } finally {
                reader.dispose();
                iis.close();
            }
        } else {
            throw new IOException("不支持的图片格式");
        }
    }

    /**
     * 将格式名映射为标准扩展名
     */
    private static String mapFormatToExtension(String formatName) {
        switch (formatName.toLowerCase()) {
            case "jpeg":
            case "jpg":
                return ".jpg";
            case "png":
                return ".png";
            case "gif":
                return ".gif";
            case "bmp":
                return ".bmp";
            default:
                return "." + formatName.toLowerCase();
        }
    }

    /**
     * 根据图片url字符串提取原始文件名（如果url中包含的话）
     *
     * @param imageUrl
     * @return
     */
    public static String extractFileNameFromUrl(String imageUrl) {
        try {
            // 精确截取最后一个/后的内容（包括查询参数中的文件名）
            String path = new URL(imageUrl).getPath();
            String baseName = path.substring(path.lastIndexOf('/') + 1);

            // 验证必须包含扩展名（如.jpg/.png等）
            if (baseName.contains(".") && baseName.length() > 4) {
                return baseName.split("\\?")[0]; // 去除可能的查询参数
            }
        } catch (Exception e) {
            log.warn("解析URL文件名异常: " + imageUrl, e);
        }
        return null; // 不符合要求时返回null
    }

    /**
     * 删除文件夹，目前主要用于接收换脸图片以后产生的废弃文件
     *
     * @param path
     * @throws IOException
     */
    public static void deleteDirectory(Path path) throws IOException {
        if (Files.exists(path)) {
            Files.walk(path)
                    //使用自然顺序的反向顺序。先删里面的内容，再删空目录，最后删主目录。
                    .sorted(Comparator.reverseOrder())
                    .forEach(p -> {
                        try {
                            Files.delete(p);
                        } catch (IOException e) {
                            // 可以改为 log.warn 或 System.err.println
                            log.warn("无法删除: " + p + " (" + e.getMessage() + ")");
                        }
                    });
        }
    }

    /**
     * 判断传过来的url是否为图片
     *
     * @param imageUrlStr
     * @return
     * @throws Exception
     */
    public static boolean isImageUrl(String imageUrlStr) throws IOException {
        URL url = new URL(imageUrlStr);
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        // 只获取头部信息，不下载完整文件
        connection.setRequestProperty("Range", "bytes=0-0");

        int responseCode = connection.getResponseCode();
        String contentType = connection.getContentType();
        return (responseCode == 200 || responseCode == 206) && contentType != null && contentType.startsWith("image/");
    }

    /**
     * 递归删除文件夹（包含所有子文件和子目录）
     * @param dir 目标文件夹路径
     * @return 是否删除成功
     */
    public static boolean deleteDirectory(File dir){
        if (!dir.exists()) return true;

        File[] files = dir.listFiles();
        if (files != null) {
            for (File file : files) {
                if (file.isDirectory()) {
                    deleteDirectory(file); // 递归删除子目录
                } else {
                    file.delete(); // 删除文件
                }
            }
        }
        return dir.delete(); // 删除空文件夹
    }

    private static boolean isEqualsToExpected(String fileName, String[] expectedExtensions) {
        // 获取后缀名
        String fileExtension = "";
        int dotIndex = fileName.lastIndexOf(".");
        if (dotIndex != -1 && dotIndex < fileName.length() - 1) {
            fileExtension = fileName.substring(dotIndex + 1);
        }
        for (String extension : expectedExtensions) {
            if (fileExtension.equalsIgnoreCase(extension)) {
                return true;
            }
        }
        return false;
    }
}
